<!--
 * @moduleName: 下拉树组件
 * @Author: dawdler
 * @Date: 2018-12-19 14:03:03
 * @LastModifiedBy: dawdler
 * @LastEditTime: 2019-04-01 15:58:58
 * @ModifiedBy: YJ 20190524 15:08
 -->
<template>
  <div class="uni-tree-dialog">
    <el-dialog class="el-row__userDialog" :visible.sync="visible" :title="title" :close-on-click-modal="false"
               :close-on-press-escape="false" :width="styles.width" append-to-body>
      <el-input v-if="propsTreeParams.filterable" v-model="keywords" size="mini" class="input-with-select mb10" @change="_searchFun"
                clearable>
        <el-button slot="append" icon="el-icon-search" @click="_searchFun"></el-button>
      </el-input>
      <!-- 树列表 -->
      <el-tree ref="tree" v-show="treeData.length>0" v-bind="propsTreeParams" :data="treeData" :node-key="propsValue"
               :draggable="false" :current-node-key="ids.length>0?ids[0]:''"
               :show-checkbox="propsTreeParams.multiple"
               :default-expand-all="true"
               :expand-on-click-node="false"
               :check-on-click-node="true"
               :filter-node-method="_filterFun"
               @node-click="_treeNodeClickFun"
               @check="_treeCheckFun"></el-tree>
      <!-- 暂无数据 -->
      <div v-if="treeData.length===0" class="no-data">no data</div>
      <div slot="footer" class="dialog-footer">
        <el-button @click="visible = false">取 消</el-button>
        <el-button type="primary" @click="_handleBackFun">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>
<style>
  .mb10 {
    margin-bottom: 10px;
  }

  .no-data {
    height: 32px;
    line-height: 32px;
    font-size: 14px;
    color: #cccccc;
    text-align: center;
  }
</style>
<script>
const _treeParams = {
  title: '',
  multiple: true,
  clickParent: false,
  filterable: false,
  props: {
    children: 'children',
    label: 'name',
    value: 'id',
    disabled: 'disabled'
  }
}
// @group api
export default {
  name: 'uni-tree-dialog',
  props: {
    // v-model,存储的是treeParams.data里面的id
    // el-tree data
    data: {
      type: Array,
      default () {
        return []
      }
    },
    // el-tree url
    treeUrl: {
      type: String,
      default () {
        return ''
      }
    },
    // el-tree url para
    treeUrlParams: {
      type: Object,
      default () {
        return {}
      }
    },
    // el-select样式
    styles: {
      type: Object,
      default () {
        return { width: '100%' }
      }
    },
    // pop的时候是否刷新数据
    refreshData: {
      type: Boolean,
      default () {
        return false
      }
    },
    /*
    下拉树参数，几乎支持el-tree所有的API<br>
     取消参数:<br>
    `:show-checkbox="selectParams.multiple"`<br>
    使用下拉框参数multiple判断是否对树进行多选<br>
    取消对el-tree的人为传参show-checkbox<br>
    `:node-key="propsValue"`     自动获取treeParams.props.value<br>
    `:draggable="false"`         屏蔽拖动
    */
    treeParams: {
      type: Object,
      /*
      Object默认参数：<br><br>
      在有子级的情况下是否点击父级关闭弹出框,false 只能点击子级关闭弹出框：`clickParent: false`<br><br>
      是否显示搜索框：<br>
      `filterable: false`<br><br>
      下拉树的数据：<br>
      `data:[]`<br><br>
      下拉树的props：<br>
      `props: {`<br>
          `children: 'children',`<br>
          `label: 'name',`<br>
          `value: 'flowId',`<br>
          `disabled: 'disabled'`<br>
      `}`
      */
      default () {
        return { ..._treeParams }
      }
    }
  },
  data () {
    return {
      propsValue: 'id',
      propsLabel: 'name',
      propsDisabled: 'disabled',
      propsChildren: 'children',
      propsTreeParams: _treeParams,
      keywords: '',
      labels: '', // 存储名称，用于下拉框显示内容
      ids: [], // 存储id
      selectNodes: [], // 选中数据
      visible: false, // popover v-model
      width: '30%',
      title: '',
      treeData: []
    }
  },
  watch: {
    ids: function (val) {
    },
    value: function (val) {
      if (this.ids !== val) {
        if (this.propsTreeParams.multiple) {
          this.ids = val
        } else {
          this.ids = val === '' ? [] : [val]
        }
      }
    },
    data: function (val) {
      this.treeData = val
    },
    treeUrl: function (val) {
      this._treeDataFromUrl(val)
    },
    visible: function (val) {
      if (val && this.refreshData) {
        this._loadTreeData()
      }
    }
  },
  created () {
    // 整合集合props
    this.propsTreeParams = {
      ..._treeParams,
      ...this.treeParams
    }
    const { props } = this.propsTreeParams
    this.propsValue = props.value
    this.propsLabel = props.label
    this.propsDisabled = props.disabled
    this.propsChildren = props.children
    this.title = this.propsTreeParams.title

    if (props.multiple) {
      this.ids = this.value
    } else {
      this.ids = this.value instanceof Array ? this.value : [this.value]
    }
    this._loadTreeData()
  },
  methods: {
    init () {
      this.visible = true
    },
    _loadTreeData () {
      // 优先url提供的数据
      if (this.treeUrl) {
        this._treeDataFromUrl(this.treeUrl)
      } else {
        this.treeData = this.data
      }
    },
    /**
     * 支持从URL中获取数据
     */
    _treeDataFromUrl (val) {
      if (val) {
        this.$http.get(val, { params: this.treeUrlParams }).then(({ data: res }) => {
          if (res.code !== 0) {
            throw new Error(res.msg)
          }
          this.treeData = res.data
        }).catch(() => { })
      }
    },
    // 输入文本框输入内容抛出
    _searchFun () {
      /*
      对外抛出搜索方法，自行判断是走后台查询，还是前端过滤<br>
      前端过滤：this.$refs.treeSelect.$refs.tree.filter(value)<br>
      后台查询：this.$refs.treeSelect.treeDataUpdateFun(data)
      */
      this.$emit('searchFun', this.keywords)
    },
    //  根据id筛选当前树名称，以及选中树列表
    _setSelectNodeFun (ids) {
      const el = this.$refs.tree
      if (!el) {
        throw new Error(`can't find tree dom`)
      }
      const { multiple } = this.propsTreeParams
      // 长度为0，清空选择
      if (ids.length === 0 || this.treeData.length === 0) {
        this.labels = multiple ? [] : ''
        if (multiple) {
          el.setCheckedKeys([])
        } else {
          el.setCurrentKey('')
        }
        return
      }
      if (multiple) {
        el.setCheckedKeys(ids)
        this.labels = el.getCheckedNodes().map(item => item[this.propsLabel]) || []
      } else {
        el.setCurrentKey(ids[0])
        if (el.getCurrentNode()) {
          this.labels = el.getCurrentNode()[this.propsLabel]
        } else {
          this.labels = ''
        }
      }
    },
    // 树过滤
    _filterFun (value, data, node) {
      if (!value) return true
      return data[this.propsLabel].indexOf(value) !== -1
    },
    // 树点击
    _treeNodeClickFun (data, node, vm) {
      const { multiple, clickParent } = this.propsTreeParams
      const { propsValue, propsChildren, propsDisabled } = this
      if (data[propsDisabled]) {
        this.$message({
          message: '节点被禁用',
          type: 'error',
          duration: 500,
          onClose: () => {
          }
        })
        // 禁用
        return
      }
      if (node.checked) {
        const value = data[this.propsValue]
        this.ids = this.ids.filter(id => id !== value)
      } else {
        if (!multiple) {
          // 多选，不关闭，单选，判断是否允许点击父级关闭弹出框
          if (!clickParent) {
            const children = data[propsChildren]
            // 如果不允许点击父级,自身为末级，允许点击之后关闭
            if (!children || children.length === 0) {
              this.ids = [data[propsValue]]
            } else {
              this.$message({
                message: '父级节点不允许被选中',
                type: 'error',
                duration: 500,
                onClose: () => {
                }
              })
              // 不允许父级，阻止继续派发
              return false
            }
          } else {
            this.ids = [data[propsValue]]
            this.visible = false
          }
        } else {
          this.ids.push(data[propsValue])
        }
      }
    },
    // 树勾选
    _treeCheckFun (data, node, vm) {
      this.ids = []
      const { propsValue } = this
      node.checkedNodes.forEach(item => {
        this.ids.push(item[propsValue])
      })
    },
    /**
     * @vuese
     * 树列表更新数据
     * @arg Array
     */
    treeDataUpdateFun (data) {
      this.treeData = data
      // // 数据更新后，刷新select显示 等待DOM做延时
      setTimeout(() => {
        this._setSelectNodeFun(this.ids)
      }, 100)
    },
    /**
     * @vuese
     * 本地过滤方法
     * @arg String
     */
    filterFun (val) {
      this.$refs.tree.filter(val)
    },
    // 确定
    _handleBackFun () {
      if (this.propsTreeParams.multiple) {
        this.$emit('backFun', this.$refs.tree.getCheckedNodes())
      } else {
        let temp = []
        temp.push(this.$refs.tree.getCurrentNode())
        this.$emit('backFun', temp)
      }
      this.visible = false
    }
  },
  components: {}
}
</script>
